/*
--------------------------------------------------------------------------------
- 文件：store.c

- 模块：st

- 作用：存储语法分析模块输出的：符号记录／块内容／重定位记录。
        不仅仅存储，还可以查询和修改已有内容。
        甚至可以把这个内部存储格式转储到 ELF 文件的功能加入本模块。
        进一步，可以填加读入 ELF 文件内容，转储为本内部格式。
        
- 记录：2004.11.23 建立，version 0.1 ：王明东
 
--------------------------------------------------------------------------------
*/

/* ---- 引入头文件 -----------------------------------------------------------*/
#include <string.h>
#include <assert.h>
#include "area.h"
#include "store.h"
#include "elf.h"


/* ---- 宏定义----------------------------------------------------------------*/
// 这三个宏定义用来分解及合成块头表中 info 域。
#define  TYPE_OF_INFO(i)        (i>>8)
#define  ALIGN_OF_INFO(i)       (i&0xff)
#define  TYPE_AND_ALIGN(t,a)    ((t<<8) + a)


/* ---- 数据类型 -------------------------------------------------------------*/
typedef  struct
{
    tetra  hash_table[256];   /* 哈希表，用于符号的快速查找           */
    tetra  str_area;          /* 字符串表，存储在符号表的中符号的名字 */
    tetra  sym_area;          /* 符号表，有相同哈希值的符号构成一个链 */
    tetra  sec_hdr_area;      /* 段头表，其中是用已定义的段及重定位段 */
} st_context_data;

typedef  struct
{
    tetra  name;      /* */
    tetra  info;      /* 31~8: shidx, 7~4: type, 3~0: bind    */
    tetra  next;      /* 用于 hash 操作的单链表, 它的值就是   *
                     * area 中的偏移量，而不是索引值        */
    octa  value;  /* 符号的偏移或其它意义     */
    octa  size;   /* 符号代表的数据所占的空间 */
} st_symbol_data;


typedef  struct
{
    tetra  name;
    tetra  info;          /* 11~8: type, 7~0: align   */
    tetra  data_area;     /* 块的真正数据这个区中     */
    tetra  reloc_area;    /* 块对应的重定位表在这个区 */
} st_section_data;

typedef  struct
{
    tetra  type;
    tetra  symbol;
    octa  added;
} st_reloc_data;

/* ---- 数据结构 -------------------------------------------------------------*/
static  tetra  root = AREA_INVALID_ID;


/* ---- 局部函数定义 ---------------------------------------------------------*/

/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   根据字符串产生一个哈希值，这个哈希值在 0 和 255 之间.
// 
// 输入：
//   str : 指向一个 utf32 格式的字符串。
// 
// 返回：
//   返回算得的哈希值，闭区间 [0,255] 。
//   
// 注意：
//   由于不想在返回值中返回 一个非法值，表示字符串数据不合法。
//   所以这里有个默认前提，就是 str 不为空，且指向的字符串不能为空( 长度为 0 ).
//   所以这两个前提由调用函数来保证。
//   
////////////////////////////////////////////////////////////////////////////////
*/
static  tetra  st_hash( tetra *  str )
{
    tetra  len;
    
    // 先计算长度。
    len = utf32_strlen( str );
    assert( len != 0 );
    // 产生哈希值的三个元素是：字符串的长度，第一个字符值，最后一个字符的值。
    // len, str[0], str[len-1];
    // 7~6 :   5~3  :    2~0 ;
    return (((len&0x3) << 6) | ((str[0]&0x7) << 3) | (str[len-1]&0x7));
}


/* ---- 函数定义 -------------------------------------------------------------*/

/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   创建存储目标代码的模块上下文。
// 
// 输入：
//   无。

// 返回：
//   上下文数据结构的指针。
//   
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_init_context()
{
    st_context_data  context;
    st_symbol_data  symbol;
    st_section_data  section;
    tetra  temp;
    
    if( root == AREA_INVALID_ID )
    {
        root = area_create( 1 );
        if( root == AREA_INVALID_ID )
        {
            return STORE_INVALID_ID;
        }

        // 初始化为全 0 。
        memset( &context, 0, sizeof(st_context_data) );    
        area_add_data( root, sizeof(st_context_data), &context );
        temp = area_add_data( root, 0, NULL );
        assert( temp == sizeof(st_context_data) );
    }
    
    // 无论是第一次调用还是其它情况，都会执行这里。
    
    // 初始化为全 0 。
    memset( &context, 0, sizeof(st_context_data) );    

    /* 为每个组件创件 area */
    context.str_area = area_create( 1 );
    assert( context.str_area != AREA_INVALID_ID );
    
    context.sym_area = area_create( 1 );
    assert( context.sym_area != AREA_INVALID_ID );
    
    context.sec_hdr_area = area_create( 1 );
    assert( context.sym_area != AREA_INVALID_ID );

    /* 这里使用 utf32 存储 字符串，应该是 utf8 更高效一些。
     * 以后考虑更改。
     */
    /* str 的第 0 个字符是 0 ..*/
    temp = 0;
    area_add_data( context.str_area, sizeof(tetra), &temp );
    
    /* sym 的第 0 个元素也应是空的 */
    memset( &symbol, 0, sizeof(st_symbol_data) );
    area_add_data( context.sym_area, sizeof(st_symbol_data), &symbol );
    
    /* section_header 的第一个元素也是空的 */
    memset( &section, 0, sizeof(st_section_data) );
    area_add_data( context.sec_hdr_area, sizeof(st_section_data), &section );

    temp = area_add_data( root, sizeof(st_context_data), &context );
    return ( temp / sizeof(st_context_data) );
}

/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   创建存储目标代码的模块上下文。
// 
// 输入：
//   st_ct  要删除的存储结构的句柄。
//
// 返回：
//   无。
//  
// 注意：
//   慎之，慎之，这个树状结构，要从树叶开始释放资源 。
////////////////////////////////////////////////////////////////////////////////
*/
void  st_fini_context( tetra st_ct )
{
    st_context_data  context;
    st_section_data  section;
    tetra  i, j;
       
    // 参数检验。
    assert( st_ct == STORE_INVALID_ID );
    
    // 读出这个 context 的内容，包括了 hash 表的内容，有点浪费。
    i = area_read_data( root, st_ct * sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );
    
    // 删除字符串表的 area .
    area_delete( context.str_area );
    
    // 删除符号表对 area .
    area_delete( context.sym_area );
    
    // 删除块头表..
    // 取得 section_hdr 表的长度，记住第一个元素是空的。
    i = area_add_data( context.sec_hdr_area, 0, NULL );
    j = sizeof( st_section_data );
    while( j < i )
    {
        // 读出一个块头部。
        area_read_data( context.sec_hdr_area, j, sizeof(st_section_data), &section );
        
        // 判断块的类型，只有 text 和 data 块才有 data 和 reloc 数据。
        if( TYPE_OF_INFO( section.info ) == ST_SEC_TYPE_TEXT 
            || TYPE_OF_INFO( section.info ) == ST_SEC_TYPE_DATA )
        {
            area_delete( section.data_area );
            area_delete( section.reloc_area );
        }
        else if( TYPE_OF_INFO(section.info) == ST_SEC_TYPE_BSS )
        {
            // nothing.
        }
        else
        {
            // nothing..
            assert( 0 );
        }
    }
    
    // 好了，应该可以了。 
}


/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   向存储结构中添加符号记录。
// 
// 输入：
//     st_ct : 所操作的存储结构的句柄。
//   p_st_sm : 要添加的符号的定义。
//
// 返回：
//   返回在存储结构中唯一标志这个符号的索引值。
//   SYMBOL_INVALID_ID (0)，表示已存在同名的符号定义。
// 
// 注意：
//   本实现不支持不同类型而同名的符号共存。
//   将来可以考虑实现在这个需求。
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_add_symbol( tetra st_ct, st_symbol_t * p_st_sm )
{
    st_context_data  context;
    st_symbol_data  symbol;
    tetra  i, j, k;
    
    
    // 取得 context 信息。
    assert( root != AREA_INVALID_ID );
    i = area_read_data( root, st_ct*sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );
    
    // 计算符号名字的哈希值。
    // 首先保证两点： 
    //   符号的名字字符串指针不能为空。
    //   符号的第一个字符不能是 0， 就是长度不能为 0 。
    assert( p_st_sm->name != NULL );
    assert( p_st_sm->name[0] != 0 );
    i = st_hash( p_st_sm->name );

   
    // 根据哈希值，在数组 hash_table 中取链中第一个符号的索引值。
    j = context.hash_table[i];

    if( j != 0 )
    {
        // 已经有这个 哈希值 的符号被加入。
        // 需要比较链中的所有符号的名字，确定是否重复定义。
        while( j != 0 )
        {
            k = area_read_data( context.sym_area, j, sizeof(st_symbol_data), &symbol );
            assert( k == sizeof(st_symbol_data) );
            if( area_compare_str(context.str_area, symbol.name, p_st_sm->name) == 0 )
            {
                // 发现重复定义。
                return SYMBOL_INVALID_ID;
            }
            
            // 记录前一个位置，用于添加。
            i = j;
            j = symbol.next;
        }
        
        // 预计会把这个 符号 加到最后的。
        // 先取它的未来偏移量，存到链中最后一个符号的 next 中。
        k = area_add_data( context.sym_area, 0 , NULL );
        symbol.next = k;
        area_write_data( context.sym_area, i, sizeof(st_symbol_data), &symbol );
    }

    else
    {
        // 说明还没有这个 哈希值 的符号被加入。
        // 预计会把这个 符号 加到最后的。
        // 先取它的未来偏移量，存到哈希表中。
        k = area_add_data( context.sym_area, 0 , NULL );
        context.hash_table[i] = k;
        
        // 由于哈希表的值已经改变，需要写入到 root area 中。
        area_write_data( root, st_ct*sizeof(st_context_data), sizeof(st_context_data), &context );
    }

    // 好了，终于释放了局部变量 symbol 的值。
    // 可以用它来存储 主角 的值了。
    // 1) 存名字，取得偏移量。
    symbol.name = area_add_str( context.str_area, p_st_sm->name );
    symbol.info = (p_st_sm->shndx << 8) + (p_st_sm->type << 4) + p_st_sm->bind;
    symbol.next = 0;
    symbol.value = p_st_sm->value;
    symbol.size = p_st_sm->size;
    
    // 2) 把符号写入 sym_area  中。
    k = area_add_data( context.sym_area, sizeof(st_symbol_data), &symbol );

	// 返回这个符号对 id 值。
	return( k / sizeof(st_symbol_data) );
}


/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   在存储结构中搜索这个符号记录，只按符号的名字搜索。
// 
// 输入：
//     st_ct : 所操作的存储结构的句柄。
//   p_st_sm : 要搜索的符号的数据结构，只有其中的 name 有意义。
//
// 输出：
//   p_st_sm : 如果真的存在这个名字的符号，返回这个符号的定义信息。
//
// 返回：
//   返回在存储结构中唯一标志这个符号的索引值。
//   SYMBOL_INVALID_ID (0) 表示没有这个符号的定义。
//  
// 注意：
//   名字对重要性，依赖名字来搜索，其它因素被忽略。
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_search_symbol( tetra st_ct, st_symbol_t * p_st_sm )
{
    st_context_data  context;
    st_symbol_data  symbol;
    tetra  i, j, k;
    
    
    // 取得 context 信息。
    assert( root != AREA_INVALID_ID );
    i = area_read_data( root, st_ct*sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );
    
    // 计算符号名字的哈希值。
    // 首先保证两点： 
    //   符号的名字字符串指针不能为空。
    //   符号的第一个字符不能是 0， 就是长度不能为 0 。
    assert( p_st_sm->name != NULL );
    assert( p_st_sm->name[0] != 0 );
    i = st_hash( p_st_sm->name );
    
    // 根据哈希值，在数组 hash_table 中取链中第一个符号的索引值。
    j = context.hash_table[i];
    if( j == 0 )
    {
        // 说明还没有这个 哈希值 的符号被加入。
        // 在符号表也不会有这个符号。
        // 直接返回查找失败。
        return SYMBOL_INVALID_ID;
    }

    // 已经有这个 哈希值 的符号被加入。
    // 需要比较链中的所有符号的名字，确定是否是要查找的符号。
    while( j != 0 )
    {
        k = area_read_data( context.sym_area, j, sizeof(st_symbol_data), &symbol );
        assert( k == sizeof(st_symbol_data) );
        if( area_compare_str(context.str_area, symbol.name, p_st_sm->name) == 0 )
        {
        	// 查找命中，返回这个符号的 id 值。
        	// 还要返回这个符号对信息。
            p_st_sm->bind = (symbol.info ) & 0xf;
        	p_st_sm->type = (symbol.info >> 4) & 0xf;
        	p_st_sm->shndx = (symbol.info >> 8) & 0xffffff;
            p_st_sm->value = symbol.value;
            p_st_sm->size = symbol.size;
                
        	return( j / sizeof(st_symbol_data) );
        }

        // 取得链中下一个结点，用于下一次循环中。
        j = symbol.next;
    }

    // 在 while 循环中找不到，那就是没有定义。
    return SYMBOL_INVALID_ID;
}


/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   在存储结构中根据给定的名子搜索符号，如果存在，则使用结构中的值更新这个
//   符号的定义。
//
// 输入：
//     st_ct : 所操作的存储结构的句柄。
//   p_st_sm : 要添加的符号的定义。
//
// 返回：
//   返回在存储结构中唯一标志这个符号的索引值。
//   SYMBOL_INVALID_ID (0) 表示没有这个符号的定义。
// 
// 注意：
//   没有..
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_modify_symbol( tetra st_ct, st_symbol_t * p_st_sm )
{
    // 先不实现，看看有没有需求再说。
    return SYMBOL_INVALID_ID;
}


/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   块的创建.
//   
//
// 输入：
//     st_ct : 所操作的存储结构的句柄。
//   p_st_se : 有关块对描述信息。
//
// 返回：
//   返回在存储结构中唯一标志这个块的索引值。
//   SECTION_INVALID_ID (0) ，表示创建失败。
// 
// 注意：
//   没有..
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_add_section( tetra st_ct, st_section_t * p_st_se )
{
    st_context_data  context;
    st_section_data  section;
    st_symbol_t  sec_name;
    tetra  i,j;
    
    // 检查。
    assert( root != AREA_INVALID_ID );
    assert( st_ct != STORE_INVALID_ID );

    // 读出 context .
    i = area_read_data( root, st_ct * sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data ) );
    assert( context.sec_hdr_area != AREA_INVALID_ID );
    i = area_add_data( context.sec_hdr_area, 0, NULL );
    
    // 转化数据结构。
    // 首先是把块的名字加入到符号表中，附带看看有没有重复定义。
    sec_name.name = p_st_se->name;
    sec_name.type = ST_SYM_TYPE_SECTION;
    sec_name.bind = p_st_se->type;      // 复用。
    sec_name.shndx = i / sizeof(st_section_data );
    sec_name.value = 0;
    sec_name.size = 0;

    section.name = st_add_symbol( st_ct, &sec_name );
    if( section.name == SYMBOL_INVALID_ID )
    {
        // 说明有同名符号定义.
        return SECTION_INVALID_ID;
    }

    // 接着是 info , 之前应该是检验。
    section.info = TYPE_AND_ALIGN( p_st_se->type, p_st_se->align );

    // 再有是 data_area 和 reloc_area;
    if( p_st_se->type == ST_SEC_TYPE_DATA || p_st_se->type == ST_SEC_TYPE_TEXT )
    {
        section.data_area = area_create( 1 );
        section.reloc_area = area_create( 1 );

        // 在 reoc_area 中加入一个空对 reloc 结构。
    }
    else
    {
        section.data_area = AREA_INVALID_ID;
        section.reloc_area = AREA_INVALID_ID;
    }

    
    // 加入...
    i = area_add_data( context.sec_hdr_area, sizeof(st_section_data), &section );
   
    return (i / sizeof(st_section_data ));
}


/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   在某个块中添加数据.
//   
//
// 输入：
//     st_ct : 所操作的存储结构的句柄。
//    sec_id : 有关块对描述信息。
//       len : 要填加的数据的长度。
//       buf : 指向要填加的数据。
//
// 返回：
//   被填加的数据在这个块中对偏移量。
//   -1 表示生失败。
// 
// 注意：
//   没有..
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_section_add_data( tetra st_ct, tetra sec_id, tetra len, void * buf )
{
    st_context_data  context;
    st_section_data  section;
    tetra  i;
    
    // 读出 context 和 section .
    assert( root != AREA_INVALID_ID );
    assert( st_ct != STORE_INVALID_ID );
    assert( sec_id != SECTION_INVALID_ID );

    printf("add data to section : len=%d\n", len );
    for( i=0; i<len; i++ )
    {
        printf("%02X ", ((byte *)buf)[i] );
    }
    printf("\n");
    
    i = area_read_data( root, st_ct * sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );


    i = area_read_data( context.sec_hdr_area, sec_id * sizeof(st_section_data), sizeof(st_section_data), &section );
    assert( i == sizeof(st_section_data) );

    // bss 段的特殊处理。
    if( TYPE_OF_INFO(section.info) == ST_SEC_TYPE_BSS )
    {
        section.reloc_area += len;
        area_write_data( context.sec_hdr_area, sec_id * sizeof(st_section_data), sizeof(st_section_data), &section );
        return  section.reloc_area;
    }
    
    assert( section.data_area != AREA_INVALID_ID );
    i = area_add_data( section.data_area, len, buf );

    return i;
}

/*
////////////////////////////////////////////////////////////////////////////////
// 功能：
//   在某个块中添加重定位信息.
//   
//
// 输入：
//     st_ct : 所操作的存储结构的句柄。
//    sec_id : 有关块对描述信息。
//       len : 要填加的数据的长度。
//       buf : 指向要填加的数据。
//
// 返回：
//   重定位的 id .
//   0 表示生失败。
// 
// 注意：
//   没有..
////////////////////////////////////////////////////////////////////////////////
*/
tetra  st_section_add_relocate( tetra st_ct, tetra sec_id, st_relocate_t *  p_st_re )
{
    st_context_data  context;
    st_section_data  section;
    st_reloc_data  relocate;
    tetra  i;
    
    // 读出 context 和 section .
    assert( root != AREA_INVALID_ID );
    assert( st_ct != STORE_INVALID_ID );
    assert( sec_id != SECTION_INVALID_ID );

    i = area_read_data( root, st_ct * sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );

    i = area_read_data( context.sec_hdr_area, sec_id * sizeof(st_section_data), sizeof(st_section_data), &section );
    assert( i == sizeof(st_section_data) );

    // 
    // bss 段的特殊处理。
    assert( TYPE_OF_INFO(section.info) != ST_SEC_TYPE_BSS );

    assert( section.reloc_area != AREA_INVALID_ID );

    //
    relocate.type = p_st_re->type;
    relocate.symbol = p_st_re->symbol_id;
    relocate.added = 0;

    i = area_add_data( section.reloc_area, sizeof(st_reloc_data), &relocate );

    return i/sizeof(st_reloc_data);
}

tetra  st_dume_str( tetra  str_area, tetra  strid )
{
    return 0;
}

tetra  st_dump_relc(tetra  relc_area )
{
    return 0;
}

tetra  st_dump_data(tetra  data_area )
{
    tetra  i, j, k, m;
    byte  tempbuf[16];
    
    i = area_add_data( data_area, 0, NULL );
    if( i == 0 )
    {
        printf( "  this data area total len is zero.. NONE..\n" );
        return 0;
    }

    printf("    ");
    for( j=0; j<i; j+=16 )
    {
        k = area_read_data( data_area, j, 16, tempbuf );
        printf( "k=%d\n", k );
        for( m=0; m<k; m++ )
        {
            printf("%02X ", tempbuf[m] );
        }

         printf("\n    ");
    }
    
    return 0;
}

tetra  st_dump_sym_tbl( tetra sym_area, tetra  str_area )
{
    tetra  i, j, k;
    st_symbol_data  tmp_sym;
    
    printf("Dump symble table :  %d.................\n", sym_area );

    i = area_add_data( sym_area, 0, NULL );

    assert( i != 0 );
    j = i % sizeof( st_symbol_data );
    if( j != 0 )
    {
        printf("attation..\n");
        printf("symbole total len : %d , sizeof(st_symbol_data) : %d\n", j, sizeof(st_symbol_data) );
        return 0;
    }

    j = i / sizeof(st_symbol_data);

    for( k=0; k<j; k++ )
    {
        printf("this is symbole %d info......\n", k );
        i = area_read_data( sym_area, k*sizeof(st_symbol_data), sizeof(st_symbol_data), &tmp_sym );
        assert( i == sizeof(tmp_sym) );

        printf( "  sym name : %d\n", tmp_sym.name );
        printf( "  sym info : %08x \n", tmp_sym.info );
        printf( "  sym next : %d\n", tmp_sym.next );
        printf( "  sym value : %d\n", (tetra)(tmp_sym.value) );
        printf( "  sym size : %d\n", (tetra)(tmp_sym.size) );
    }
    
    return 0;
}

tetra  st_dump_sec_hdr( tetra  hdr_area, tetra  str_area )
{
    st_section_data  sec_hdr_data;
    tetra  i, j, k;
    
    printf("Dump section header :  %d.................\n", hdr_area );
    i = area_add_data( hdr_area, 0, NULL );

    if( i == 0 )
    {
        printf( "No exist section..\n" );
        return 0;
    }

    
    j = i % sizeof( st_section_data );
    if( j != 0 )
    {
        printf("attation..\n");
        printf("sec_hdr_area total len : %d , sizeof(st_section_data) : %d\n", i, sizeof(st_section_data) );
        return 0;
    }

    j = i / sizeof(st_section_data);
    printf( "section total number : %d \n", j );

    for( k=0; k<j; k+=1 )
    {
        printf("this is section %d info......\n", k );
        i = area_read_data( hdr_area, k*sizeof(st_section_data), sizeof(st_section_data), &sec_hdr_data );
        assert( i==sizeof(st_section_data) );

        printf( "  sec name : %d\n", sec_hdr_data.name );
        if( sec_hdr_data.name != 0 )
        {
            st_dume_str( str_area, sec_hdr_data.name );
        }
        printf( "  sec info : %d\n", sec_hdr_data.info);
        printf( "  sec data : %d\n", sec_hdr_data.data_area );
        printf( "  sec relc : %d\n", sec_hdr_data.reloc_area );
        
        if( sec_hdr_data.data_area != 0 )
        {
            printf( "  section data area : .. \n");
            st_dump_data( sec_hdr_data.data_area );
        }

        if( sec_hdr_data.reloc_area != 0 )
        {
            printf( "  section data area : .. \n");
            st_dump_relc( sec_hdr_data.reloc_area );
        }
    }


    return 0;
}


tetra  st_dump_context( tetra  st_ct  )
{
    st_context_data  context;
    st_section_data  section;

    
    tetra  i, j, k;
       
    // 参数检验。
    assert( st_ct != STORE_INVALID_ID );
    
    // 读出这个 context 的内容，包括了 hash 表的内容，有点浪费。
    i = area_read_data( root, st_ct * sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );

    /*  */
    printf("\nST context info :  .................\n");
    printf("  sec_hdr_area  : %d\n", context.sec_hdr_area );
    printf("  sym_area      : %d\n", context.sym_area );
    printf("  str_area      : %d\n", context.str_area );

#if 0
    printf("  hash_data     : " );
    for( i=0; i<256; i++ )
    {
        if(i%8==0)
        {
            printf("\n    ");
        }
        printf( "%08x ", context.hash_table[i]);
    }
#endif

    st_dump_sec_hdr( context.sec_hdr_area, context.str_area );

    st_dump_sym_tbl( context.sym_area, context.str_area );

    return 0;    

}


/*
 *
 */

/*
 *            file header :
 *   section header table :
 *             hash table :
 *           symbol table :
 *           string table :
 *             sec1 reloc :
 *             sec2 reloc :
 *                  ... ...
 *              sec1 data :
 *              sec2 data :
 *                  ... ...
 */

tetra  st_write_to_elf64( tetra stctx,  tetra * filename )
{
    Elf64_Ehdr  temp_ehdr;
    Elf64_Shdr  temp_shdr;
    FILE * fout;
    tetra  i, j, k;
    
    st_context_data  context;
    st_section_data  * psection;
    tetra  user_sec_num;    /* 用户定义的段的个数. */
    tetra  reloc_sec_num;

    tetra  shd_ofs, shd_size;
    tetra  rhd_ofs, rhd_size;
    tetra  thd_ofs, thd_size;
    tetra  hsh_ofs, hsh_size;
    tetra  str_ofs, str_size;
    tetra  sym_ofs, sym_size;
    tetra  sec_ofs, sec_size;
    tetra  rel_ofs, rel_size;
    fpos_t  temp_pos;

    /* 基本信息. */
    // 参数检验。
    assert( stctx != STORE_INVALID_ID );
    
    // 读出这个 context 的内容，包括了 hash 表的内容，有点浪费。
    i = area_read_data( root, stctx * sizeof(st_context_data), sizeof(st_context_data), &context );
    assert( i == sizeof(st_context_data) );

    /**/
    assert( context.sec_hdr_area != AREA_INVALID_ID );
    user_sec_num = area_add_data( context.sec_hdr_area, 0, NULL );
    user_sec_num = user_sec_num / sizeof(st_section_data );

    /* 默认的一个空段. */
    if( user_sec_num == 1 )
    {
        return 1;
    }

    /* 读出 string, symbol 的大小. */
    assert( context.str_area != AREA_INVALID_ID );
    i = area_add_data( context.str_area, 0, NULL );
    str_size = i;
    
    assert( context.sym_area != AREA_INVALID_ID );
    i = area_add_data( context.sym_area, 0, NULL );
    i = i / sizeof(st_symbol_data);
    i = i * sizeof(Elf64_Sym);
    sym_size = i;
    

    /* 动态资源.1 , 需要释放. */
    psection = malloc( user_sec_num * sizeof(st_section_data) );
    if( psection == NULL )
    {
        return 1;
    }
    
    i = area_read_data( context.sec_hdr_area, 0, user_sec_num * sizeof(st_section_data), psection );
    assert( i == user_sec_num * sizeof(st_section_data) );
    
    
    fsetpos( fout, sizeof(Elf64_Ehdr) );

    /* 空段头表.+ str + sym */
    shd_size = sizeof(Elf64_Shdr);
    rhd_size = 0;
    sec_size = 0;
    rel_size = 0;
    for( i=1; i<user_sec_num; i++ )
    {
        shd_size += sizeof(Elf64_Shdr);

        if( TYPE_OF_INFO(psection[i].info) != ST_SEC_TYPE_BSS )
        {
            /* 读出长度. */
            j = area_add_data( psection[i].data_area, 0, NULL );
            if( j != 0 )
            {
                sec_size += j;
                j = area_add_data( psection[i].reloc_area, 0, NULL );
                if( j > sizeof(st_reloc_data) )
                {
                    /* 需要重定位段. */
                    rhd_size += sizeof(Elf64_Shdr);

                    j = j / sizeof(st_reloc_data);
                    j = j * sizeof(Elf64_Rela);
                    rel_size += j;
                }
            }
        }
    }

    /* 到这里, 基本的 排布信息, 足够了. */
    hsh_size = 256 * sizeof(tetra);
    thd_size = 2 * sizeof(Elf64_Shdr);
    
    /* offset.. */
    shd_ofs = sizeof(Elf64_Ehdr);
    rhd_ofs = shd_ofs + shd_size;
    thd_ofs = rhd_ofs + rhd_size;
    hsh_ofs = thd_ofs + thd_size;
    sym_ofs = hsh_ofs + hsh_size;
    str_ofs = sym_ofs + sym_size;
    sec_ofs = str_ofs + str_size;
    rel_ofs = sec_ofs + sec_size;
    

    /* 文件描述符. */
    fout = fopen( "mmix_elf.o", "wb" );
    if( fout == NULL )
    {
        return 1;
    }
    
    /* 文件头 */
    /* 需要知道 section 的个数. */
    
    memset( &temp_ehdr, 0, sizeof(Elf64_Ehdr) );
    
    temp_ehdr.e_ident[EI_MAG0] = 0x7e;
    temp_ehdr.e_ident[EI_MAG1] = 'E';
    temp_ehdr.e_ident[EI_MAG2] = 'L';
    temp_ehdr.e_ident[EI_MAG3] = 'F';
    temp_ehdr.e_ident[EI_CLASS] = 0;
    temp_ehdr.e_ident[EI_DATA] = 0;
    temp_ehdr.e_ident[EI_VERSION] = 0;
    temp_ehdr.e_ident[EI_OSABI] = 0;
    temp_ehdr.e_ident[EI_ABIVERSION] = 0;

    temp_ehdr.e_type = 0;
    temp_ehdr.e_version = 0;
    temp_ehdr.e_machine = 0;
    temp_ehdr.e_entry = 0;
    temp_ehdr.e_phoff = 0;
    temp_ehdr.e_shoff = sizeof(Elf64_Ehdr);
    temp_ehdr.e_flags = 0;
    temp_ehdr.e_phentsize = 0;
    temp_ehdr.e_phnum = 0;
    temp_ehdr.e_shentsize = sizeof(Elf64_Shdr);
    temp_ehdr.e_shnum = hdr_size / sizeof(Elf64_Shdr) ;
    temp_ehdr.e_shstrndx = temp_ehdr.e_shnum - 2;
    /* 最后一个是 sym, 倒数第二个是 str. */

    /* 写入文件头. */
    temp_pos = 0;
    fsepos( fp, &temp_pos );
    fwrite( &temp_ehdr, sizeof(Elf64_Ehdr), 1, fout );

    /* 写入段头..  */
    memset( &temp_shdr, 0, sizeof(Elf64_Shdr) );
    temp_pos = shd_ofs;
    fsepos( fp, &temp_pos );
    fwrite( &temp_shdr, sizeof(Elf64_Shdr), 1, fout );
    shd_ofs += sizeof(Elf64_Shdr);
    
    for( i=1; i<user_sec_num; i++ )
    {
        k = area_add_data(psection[i].data_area, 0, NULL );
        temp_shdr.sh_name = psection[i].name;
        temp_shdr.sh_addr = 0;
        temp_shdr.sh_addralign = ALIGN_OF_INFO(psection[i].info);
        temp_shdr.sh_offset = sec_ofs;
        temp_shdr.sh_size = k;
        temp_shdr.sh_entsize = 0;


        temp_shdr.sh_info ?
        temp_shdr.sh_link ?
        
        if( TYPE_OF_INFO(psection[i].info) == ST_SEC_TYPE_TEXT )
        {
            temp_shdr.sh_type = SHT_PROGBITS;
            temp_shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
        }
        else if( TYPE_OF_INFO(psection[i].info) == ST_SEC_TYPE_DATA )
        {
            temp_shdr.sh_type = SHT_PROGBITS;
            temp_shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
        }
        else if( TYPE_OF_INFO(psection[i].info) == ST_SEC_TYPE_BSS )
        {
            temp_shdr.sh_type = SHT_NOBITS;
            temp_shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
            k = 0;
        }
        else
        {
            assert(0);
        }

        /* 写入 sec hdr . */
        temp_pos = shd_ofs;
        fsetpos( fout, &temp_pos );
        fwrite( &temp_shdr, sizeof(Elf64_Shdr), 1, fout );
        shd_ofs += sizeof(Elf64_Shdr);

        if( k != 0 )
        {
            /* 写入数据. */
            temp_pos = sec_ofs;
            fsetpos( fout, &temp_pos );
            fwrite();
            sec_ofs += k;

            /* 判断重定位. */
            j = area_add_data( psection[i].reloc_area, 0, NULL );
            if( j > sizeof(st_reloc_data) )
            {
                /* 加入重定位 sec hdr. */

                /* 加入重定位 rela data. */
            }
        }
    }

    /* 写 str, sym.. */
fsetpos(FILE *, const fpos_t *)
}

tetra  st_read_from_elf64( tetra stctx,  tetra * filename )
{
    return 0;
}

